package com.twopai.framelibrary.http;


import android.os.Environment;

import com.twopai.appbase.BaseApplication;
import com.twopai.comm.netutil.NetUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;

import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Cache;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;


/**
 * @author twopai
 */
public class RetrofitClient {
    private String BASE_URL="http://app.99djc.com/api/";
    private static volatile RetrofitClient instance;
    private DownloadListener mDownloadListener;
    // 清除线程需要用到的
    private Disposable disposable;
    private ApiManager apiService;

    private RetrofitClient() {
    }
    public static RetrofitClient getInstance() {
        if (instance == null) {
            synchronized (RetrofitClient.class) {
                if (instance == null) {
                    instance = new RetrofitClient();
                }
            }
        }
        return instance;
    }


    public ApiManager getApi(String baseUrlCur) {
        if (baseUrlCur == null) {
            baseUrlCur=BASE_URL;
        }
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrlCur)
                .client(getClient())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();        //创建—— 网络请求接口—— 实例
        apiService = retrofit.create(ApiManager.class);
        return apiService;
    }
    public RetrofitClient getApi(String baseUrlCur,DownloadListener listener) {
        mDownloadListener =listener;
        if (baseUrlCur == null) {
            baseUrlCur=BASE_URL;
        }
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrlCur)
                .client(getClient(listener))
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();        //创建—— 网络请求接口—— 实例
        apiService = retrofit.create(ApiManager.class);
        return this;
    }


    public OkHttpClient getClient(){
        //缓存路径和大小
        File httpCacheDirectory = new File(Environment.getExternalStorageDirectory(), "HttpCache");
        int cacheSize = 10 * 1024 * 1024;
        Cache cache = new Cache(httpCacheDirectory, cacheSize);

        //日志拦截器
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

        OkHttpClient httpClient = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)//设置连接超时
                .readTimeout(10, TimeUnit.SECONDS)//读取超时
                .writeTimeout(10, TimeUnit.SECONDS)//写入超时
                .addInterceptor(interceptor)//添加日志拦截器
                .addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)//添加缓存拦截器
                .cache(cache)//把缓存添加进来
                .build();
        return httpClient;
    }
    //文件上传下载
    public OkHttpClient getClient(DownloadListener listener){
        //缓存路径和大小
        File httpCacheDirectory = new File(Environment.getExternalStorageDirectory(), "HttpCache");
        int cacheSize = 10 * 1024 * 1024;
        Cache cache = new Cache(httpCacheDirectory, cacheSize);

        //日志拦截器
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

        DownloadInterceptor mInterceptor = new DownloadInterceptor(listener);
        OkHttpClient httpClient = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)//设置连接超时
                .readTimeout(10, TimeUnit.SECONDS)//读取超时
                .writeTimeout(10, TimeUnit.SECONDS)//写入超时
                .addInterceptor(mInterceptor)
//                .addInterceptor(interceptor)//添加日志拦截器
                .addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)//添加缓存拦截器
                .cache(cache)//把缓存添加进来
                .build();
        return httpClient;
    }
        //缓存拦截器，不同接口不同缓存
     Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {

            Request request = chain.request();
            Response response = chain.proceed(request);

            if (NetUtils.isNetworkConnected(BaseApplication.getInstance())) {
                String cacheControl =request.cacheControl().toString();
                return response.newBuilder()
                        .removeHeader("Pragma")//清除头信息，因为服务器如果不支持，会返回一些干扰信息，不清除下面无法生效
                        .header("Cache-Control", cacheControl)
                        .build();
            }
            return response;
        }
    };

//    //缓存拦截器，统一缓存60s
//     Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
//        @Override
//        public Response intercept(Chain chain) throws IOException {
//
//            Request request = chain.request();
//            Response response = chain.proceed(request);
//
//            if (NetUtils.isNetworkConnected(DemoApplication.getInstance())) {
//                int maxAge = 60*60*24*2;//缓存失效时间，单位为秒
//                return response.newBuilder()
//                        .removeHeader("Pragma")//清除头信息，因为服务器如果不支持，会返回一些干扰信息，不清除下面无法生效
//                        .header("Cache-Control", "public ,max-age=" + maxAge)
//                        .build();
//            }
//            return response;
//        }
//    };

    /***************************************************文件下载**************************************************/
    /**
     * 进行文件下载
     * @param url 网址
     * @param destDir 文件目录
     * @param fileName 文件名称
     */
    public void downloadFile(String url, String destDir, final String fileName) {
        if (destDir == null||destDir.trim().isEmpty()) {
            destDir="";
        }
        if (fileName == null||fileName.trim().isEmpty()) {
            destDir="fileName";
        }
        dispose();
        mDownloadListener.onStartDownload();
        final String finalDestDir = destDir;
        apiService
                .download(url)
                .subscribeOn(Schedulers.io())//请求网络 在调度者的io线程
                .observeOn(Schedulers.io()) //指定线程保存文件
                .observeOn(Schedulers.computation())
                .map(new Function<ResponseBody, File>() {
                    @Override
                    public File apply(ResponseBody responseBody) throws Exception {
                        return saveFile(responseBody.byteStream(), finalDestDir, fileName);
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new BaseDownloadObserver<File>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        disposable = d;
                    }

                    @Override
                    protected void onDownloadSuccess(File file) {
                        mDownloadListener.onFinishDownload(file);
                    }

                    @Override
                    protected void onDownloadError(Throwable e) {
                        mDownloadListener.onFail(e);
                    }
                });
    }
    /**
     * 销毁
     */
    public void dispose() {
        if (disposable != null && !disposable.isDisposed()) {
            disposable.dispose();
        }
    }
    /**
     * 销毁
     */
    public void destroy() {
        if (mDownloadListener != null) {
            mDownloadListener=null;
        }
    }


    /**
     * 将文件写入本地
     *
     * @param destFileDir  目标文件夹
     * @param destFileName 目标文件名
     * @return 写入完成的文件
     * @throws IOException IO异常
     */
    private File saveFile(InputStream is, String destFileDir, String destFileName) throws IOException {
        byte[] buf = new byte[2048];
        int len;
        FileOutputStream fos = null;
        try {
            File dir = new File(destFileDir);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            File file = new File(dir, destFileName);
            if (file.exists()) {
                file.delete();
            }
            fos = new FileOutputStream(file);
            while ((len = is.read(buf)) != -1) {
                fos.write(buf, 0, len);
            }
            fos.flush();
            return file;

        } finally {
            try {
                if (is != null) is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (fos != null) fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
